package pl.edu.agh.io.gpstracker.client.widget;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import pl.edu.agh.io.gpstracker.client.action.FindAllUsersAction;
import pl.edu.agh.io.gpstracker.client.action.FindTrackByUserAction;
import pl.edu.agh.io.gpstracker.client.action.GetLastPositionForTrack;
import pl.edu.agh.io.gpstracker.client.dto.NodeDto;
import pl.edu.agh.io.gpstracker.client.dto.TrackDto;
import pl.edu.agh.io.gpstracker.client.dto.TracksequanceDto;
import pl.edu.agh.io.gpstracker.client.dto.UserDto;
import pl.edu.agh.io.gpstracker.client.dto.UserType;
import pl.edu.agh.io.gpstracker.client.result.CollectionResult;
import pl.edu.agh.io.gpstracker.client.result.ObjectResult;
import pl.edu.agh.io.gpstracker.client.window.NewMessageWindow;

import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.Maps;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.layout.HLayout;

/**
 * 
 * @author wkedzior
 * 
 */
public class MonitoringWidget extends GenericWidget {

	private DynamicForm form;
	private SelectItem usersSelectItem;
	private SelectItem trackSelectItem;

	private MapWidget map;
	private List<TrackDto> trackOnScreen;
	private List<UserDto> usersList;
	private TrackDto selectedTrack;
	private List<Marker> markerBuffer;

	private boolean isTimmerRunning = false;
	private Timer refreshTimmer;

	public MonitoringWidget() {
		this.markerBuffer = new ArrayList<Marker>();
	}

	@Override
	protected void onInit() {
		super.onInit();
	
		Maps.loadMapsApi("", "2", false, new Runnable() {
			public void run() {
				createWidget();
			}
		});

		refreshTimmer = new Timer() {
			@Override
			public void run() {
				if (null != selectedTrack) {
					refresh(selectedTrack.getId());
				}

			}
		};
	}

	/**
	 * 
	 */
	private void createWidget() {

		HLayout trackLayout = new HLayout();
		trackLayout.setMembersMargin(5);
		trackLayout.setMargin(5);
		form = new DynamicForm();
		trackLayout.setIsGroup(true);
		trackLayout.setGroupTitle("Wybor obiektu");

		// fake
		trackSelectItem = new SelectItem();
		trackSelectItem.setWidth(300);
		trackSelectItem.setTitle("Aktywna trasa");
		trackSelectItem.addChangeHandler(new ChangeHandler() {

			@Override
			public void onChange(ChangeEvent event) {
				displaySelectedTrackFromCache(Integer.parseInt((String) event
						.getValue()));
			}
		});

		usersSelectItem = new SelectItem();
		usersSelectItem.setTitle("Uzytownik");
		usersSelectItem.addChangeHandler(new ChangeHandler() {

			@Override
			public void onChange(ChangeEvent event) {
				if (null != trackOnScreen) {
					trackOnScreen.clear();
				}
				loadTrackForUser(Integer.parseInt((String) event.getValue()));

			}
		});

		form.setFields(usersSelectItem, trackSelectItem);

		IButton show = new IButton("Wyswietl");
		show.setWidth(60);
		show.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				displaySelectedTrackFromCache(Integer
						.parseInt((String) trackSelectItem.getValue()));
			}
		});

		IButton sendMessage = new IButton("Wyslij wiadomosc");
		sendMessage.setWidth(120);
		sendMessage.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				new NewMessageWindow(getUserById(Integer
						.parseInt((String) usersSelectItem.getValue()))).show();
			}
		});

		final IButton startMonitoring = new IButton("Rozpocznij monitorownaie");
		final IButton stopMonitoring = new IButton("Zatrzymaj monitorownaie");
		stopMonitoring.setDisabled(true);
		startMonitoring.setDisabled(false);
		
		startMonitoring.setWidth(150);
		startMonitoring.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {

				if (isTimmerRunning) {
					refreshTimmer.cancel();
					isTimmerRunning = false;
				}
				isTimmerRunning = true;
				refreshTimmer.schedule(2 * 1000);
				refreshTimmer.scheduleRepeating(3 * 1000);
				if (null != selectedTrack) {
					SC.say("Monitorowanie uzytkownika <b>"
							+ selectedTrack.getUser().getLogin()
							+ " </b> rozpoczete!");
					stopMonitoring.setDisabled(false);
					startMonitoring.setDisabled(true);
				}
			}
		});

		
		stopMonitoring.setWidth(150);
		stopMonitoring.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if (isTimmerRunning) {
					refreshTimmer.cancel();
					isTimmerRunning = false;
					if (null != selectedTrack) {
						SC.say("Monitorowanie uzytkownika <b>"
								+ selectedTrack.getUser().getLogin()
								+ " </b> zakonczone!");
						stopMonitoring.setDisabled(true);
						startMonitoring.setDisabled(false);
					}
				}
			}
		});

		trackLayout.setMembers(form, sendMessage, startMonitoring, stopMonitoring);
		LatLng cawkerCity = LatLng.newInstance(50.0622, 19.9445);

		map = new MapWidget(cawkerCity, 2);
		// Add some controls for the zoom level
		map.addControl(new LargeMapControl());
		map.setZoomLevel(16);

		// Add a marker
		map.addOverlay(new Marker(cawkerCity));
		final DockLayoutPanel dock = new DockLayoutPanel(Unit.PX);
		dock.addNorth(map, 460);
		dock.setSize("880", "460");

		HLayout la = new HLayout();

		la.addMember(dock);

		setMembers(la, trackLayout);
		loadUsers();
	}

	@Override
	protected void onDraw() {
		super.onDraw();
		loadUsers();
	}

	private void loadUsers() {
		dispatcher.execute(new FindAllUsersAction(UserType.MOBILE_USER),
				new AsyncCallback<CollectionResult<UserDto>>() {

					@Override
					public void onFailure(Throwable caught) {
						SC.say(caught.toString());
					}

					@Override
					public void onSuccess(CollectionResult<UserDto> result) {
						LinkedHashMap<String, String> users = new LinkedHashMap<String, String>();
						
						for (UserDto user : result.getResult()) {
							users.put(String.valueOf(user.getId()), user
									.getLogin());
						}
						usersList = result.getResult();
						usersSelectItem.setValueMap(users);
						if (result.getResult()!=null && !result.getResult().isEmpty()){
							loadTrackForUser(result.getResult().get(0).getId());
						}
					}
				});
	}

	private void loadTrackForUser(Integer userId) {
		dispatcher.execute(new FindTrackByUserAction(userId),
				new AsyncCallback<CollectionResult<TrackDto>>() {
					@Override
					public void onFailure(Throwable caught) {
						SC.say(caught.toString());
					}

					@Override
					public void onSuccess(CollectionResult<TrackDto> result) {
						LinkedHashMap<String, String> tracks = new LinkedHashMap<String, String>();
						trackOnScreen = result.getResult();
						for (TrackDto track : result.getResult()) {
							tracks.put(String.valueOf(track.getId()), track
									.getName());
						}
						trackSelectItem.setValueMap(tracks);

					}
				});
	}

	private UserDto getUserById(Integer id) {
		UserDto user = null;
		for (UserDto track : usersList) {
			if (track.getId().equals(id)) {
				user = track;
			}
		}
		if (user == null) {
			throw new IllegalArgumentException("Wring track id!");
		}
		return user;
	}

	private void displaySelectedTrackFromCache(Integer id) {
		TrackDto selTrack = null;
		for (TrackDto track : trackOnScreen) {
			if (track.getId().longValue() == id.intValue()) {
				selTrack = track;
				break;
			}
		}
		if (selTrack == null) {
			throw new IllegalArgumentException("Wrong track id!");
		} else {
			if (selTrack.getTracksequenceList() != null
					&& !selTrack.getTracksequenceList().isEmpty()) {
				NodeDto node = selTrack.getTracksequenceList().get(
						selTrack.getTracksequenceList().size() - 1).getNode();
				LatLng point = LatLng.newInstance(node.getLongitude(), node
						.getLatitude());
				// wykaowac stary

				// Add a marker
				map.setCenter(point);
				selectedTrack = selTrack;
			} else {
				SC.say("Brak pozycji dla wybranej trasy!");
			}

		}
	}

	private void refresh(Long trackId) {
		dispatcher.execute(new GetLastPositionForTrack(trackId),
				new AsyncCallback<ObjectResult<TracksequanceDto>>() {

					@Override
					public void onFailure(Throwable caught) {
						SC.say(caught.toString());
					}

					@Override
					public void onSuccess(ObjectResult<TracksequanceDto> result) {
						NodeDto node = result.getResult().getNode();
						LatLng point = LatLng.newInstance(node.getLongitude(),
								node.getLatitude());
						// Add a marker
						for (Marker marker : markerBuffer){
							map.removeOverlay(marker);
						}
						Marker newMakrer =  new Marker(point);
						map.addOverlay(newMakrer);
						markerBuffer.add(newMakrer);
						map.setCenter(point);
					}
				});
	}

}
